package com.xinke.query.common.aspect;

import jakarta.servlet.http.HttpServletRequest;
import com.xinke.query.common.annotation.Log;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.time.Duration;
import java.time.LocalDateTime;

/**
 * 日志切面类
 */
@Aspect
@Component
public class LogAspect {
    private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);

    /**
     * 切点，所有带Log注解的方法
     */
    @Pointcut("@annotation(com.xinke.query.common.annotation.Log)")
    public void logPointCut() {
    }

    /**
     * 记录请求信息
     *
     * @param joinPoint
     */
    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            logger.info("===== 开始请求 =====");
            logger.info("log.value:{}", getLogDescription(joinPoint));
            logger.info("请求URL: {}", request.getRequestURL().toString());
            logger.info("请求方法: {}", request.getMethod());
            logger.info("客户端IP: {}", request.getRemoteAddr());
            logger.info("调用方法: {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
            logger.info("请求参数：{}.{}", joinPoint.getArgs());
        }
    }

    /**
     * 记录方法时间
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("logPointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        LocalDateTime startTime = LocalDateTime.now();
        Object result = joinPoint.proceed();
        long time = Duration.between(startTime, LocalDateTime.now()).toMillis();
        logger.info("方法耗时: {}", time);
        logger.info("===== 请求结束 =====");
        return result;
    }

    /**
     * 记录结果信息
     *
     * @param result
     */
    @AfterReturning(returning = "result", pointcut = "logPointCut()")
    public void doAfterReturning(Object result) {
        logger.info("返回结果: {}", result);

    }

    /**
     * 记录异常信息
     *
     * @param e
     */
    @AfterThrowing(pointcut = "logPointCut()", throwing = "e")
    public void doAfterThrowing(Throwable e) {
        logger.error("方法抛出异常: ", e);
        logger.info("===== 请求失败！=====");
    }

    /**
     * 获取Log的value
     *
     * @param joinPoint
     * @return
     */
    private String getLogDescription(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Log logAnnotation = method.getAnnotation(Log.class);
        return logAnnotation != null ? logAnnotation.value() : "";
    }


}
